package bch.netty.handler;

import io.netty.channel.DefaultFileRegion;
import io.netty.util.Recycler;
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.concurrent.FastThreadLocalThread;
import io.netty.util.internal.ObjectPool;
import lombok.Data;
import org.springframework.core.annotation.AnnotationUtils;

/**
 * NioServerSocketChannel的创建
 * 反射创建服务器Channel
 * 配置ChannelConfig
 * 配置Channel非阻塞
 * 初始化ID Pipeline Unsafe
 * 服务器Channel的初始化
 * 配置服务端pipeline
 * pipeline中添加acceptor
 * 注册服务端channel到Selector
 * 服务端口绑定
 * <p>
 * <p>
 * <p>
 * <p>
 * NioEventLoop
 * 创建
 * 启动
 * 服务器绑定端口
 * 新连接通过chooser选择一个nioEventLoop
 * SingleThreadEventExecutor.this.run();
 * 检测io事件selector.select(); : select系统调用将轮询的操作交给了内核来帮助我们完成，从而避免了在用户空间不断的发起轮询所带来的的系统性能开销
 * processSelectedKeys();处理io事件
 * runAllTasks();处理任务队列中的任务
 * 无锁化设计: 如果不是nioEventLoop线程，则将任务放入任务队列中
 * <p>
 * <p>
 * <p>
 * 新连接接入
 * processSelectedKeys().select().accept();
 * 创建NioSocketChannel(类似NioServerSocketChannel 区别就是感兴趣的io事件不一样)
 * acceptor为新连接创建线程NioEventLoop并注册到worker selector
 * nioSocketChannel读事件的注册(表示：我对这个连接的读事件感兴趣)
 * <p>
 * <p>
 * Pipeline
 * 初始化:创建Channel时创建DefaultChannelPipeline
 * 一个channel对应一个pipeline
 * 一个pipeline包含多个handler
 * 一个handler对应一个context
 * handlerAdded回调
 * <p>
 * InboundHandler 和 OutboundHandler 最后都会到tail head的 除非不fire
 * inbound : head -> handler -> tail
 * outbound: tail -> handler -> head
 * 使用ChannelHandlerContext则是从当前节点开始传播
 * <p>
 * exceptionCaught
 * inbound
 * 异常处理: next ->  head -> ib1 -> ib2 -> ib3 -> ... ob1 -> ob2 -> ob3 -> ... -> tail
 * 最佳实现: 最后一个handler处理异常
 * outbound : listener
 * <p>
 * decode
 * 具体子类decode --> fireChannelRead --> tail
 * {@link io.netty.handler.codec.FixedLengthFrameDecoder}
 * {@link io.netty.handler.codec.LineBasedFrameDecoder}
 * {@link io.netty.handler.codec.DelimiterBasedFrameDecoder}
 * {@link io.netty.handler.codec.LengthFieldBasedFrameDecoder}
 * <p>
 * encode
 * 具体子类encode --> invokeWriteAndFlush --> fireWrite --> head.unsafe.write --> fireFlush --> head.unsafe.flush
 */
public class Desc {
    /**
     *
     * 阻塞IO
     * 非阻塞IO
     *    SocketChannel.configureBlocking(false)
     * IO多路复用
     *   进程通过 select/poll/epoll/kqueue 等系统调用，把一批 fd 交给内核,内核帮你监视这些 fd，当某个 fd 就绪时再通知你
     *      select
     *      poll
     *      epoll
     * 信号驱动IO
     * 异步IO
     *  异步IO是基于事件驱动的，它与信号驱动IO最大的不同在于，异步IO不需要用户进程主动询问，而是由内核通知用户进程某个操作已经完成。
     *  异步IO的实现有AIO、IOCP、Proactor等。
     */

    /**
     * 数据准备阶段：
     * 在这个阶段，网络数据包到达网卡，通过DMA的方式将数据包拷贝到内存中，
     * 然后经过硬中断，软中断，
     * 接着通过内核线程ksoftirqd经过内核协议栈的处理，最终将数据发送到内核Socket的接收缓冲区中。
     * <p>
     * 数据拷贝阶段：
     * 当数据到达内核Socket的接收缓冲区中时，
     * 此时数据存在于内核空间中，
     * 需要将数据拷贝到用户空间中，才能够被应用程序读取
     */

    /**
     * 零拷贝
     *      jdk: 数据不需要读到 JVM 堆内存，而是内核直接从文件缓冲区复制到网卡缓冲区，然后通过 DMA 直接发送到网卡。
     *          {@link java.nio.channels.FileChannel#transferTo(long, long, java.nio.channels.WritableByteChannel)}
     *                  把文件直接写到 SocketChannel（发送文件）
     *          {@link java.nio.channels.FileChannel#transferFrom(java.nio.channels.ReadableByteChannel, long, long)}
     *                  从 SocketChannel 读取数据并存到文件（接收文件）
     *          {@link java.nio.MappedByteBuffer}
     *                  文件和内存的映射区域
     *                  用户态和内核态共享一块内存区域，直接访问
     *                  不需要 read()/write() 系统调用，操作直接发生在内核和用户态共享的内存区域
     *      netty:
     *          {@link io.netty.buffer.ByteBuf}
     *              slice
     *                  共享内存的部分区间
     *              duplicate
     *                  多视图共享同一底层数据
     *              wrappedBuffer
     *                  避免从 byte[] 复制
     *              retainedSlice
     *                  保证生命周期管理
     *              directBuffer
     *                  避免 JVM 堆到内核的拷贝
     *          {@link DefaultFileRegion}
     *          {@link io.netty.buffer.CompositeByteBuf} : 将多个缓冲区显示为单个合并缓冲区的虚拟缓冲区避免复制
     *              逻辑上：你看到的是一个 连续的大缓冲区（HEADBODY）
     *              物理上：header 和 body 仍然存在于 各自的内存块里，数据并没有被拷贝到一块新的内存
     *              CompositeByteBuf 内部维护的是一个 ByteBuf 列表（components），通过索引映射，把多个小块拼成一个虚拟的“大块”
     */

    public static void main(String[] args) {
        /**
         * {@link io.netty.util.concurrent.FastThreadLocal} 空间换时间  InternalThreadLocalMap数组存储 O(1)
         * 一个 ThreadLocalMap 可以存放多个 ThreadLocal 实例及其对应的值，
         * 而一个 ThreadLocal 实例可以在多个线程中被使用
         * entry中key是threadLocal本身 是弱引用
         */
        ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
        stringThreadLocal.set("hello");
        String value1 = stringThreadLocal.get();
        System.out.println("main thread value: " + value1);

        FastThreadLocal<String> fastThreadLocal = new FastThreadLocal<>();
        fastThreadLocal.set("hello");
        String value = fastThreadLocal.get();
        System.out.println("main thread value: " + value);

        new FastThreadLocalThread(() -> {
            fastThreadLocal.set("world");
            System.out.println("fastThreadLocal value in thread: " + fastThreadLocal.get());
        }).start();


        /**
         * {@link io.netty.util.Recycler}
         * {@link ObjectPool}
         *  跨线程回收 io.netty.util.internal.shaded.org.jctools.queues.MessagePassingQueue
         *  Stack vs LocalPool
         */
        Recycler<User> recycler = new Recycler<>() {
            @Override
            protected User newObject(Handle<User> handle) {
                return new User(handle);
            }
        };
        User user = recycler.get();
        user.recycle();
        User user1 = recycler.get();
        System.out.println(user == user1);
    }

    @Data
    private static class User {
        private final Recycler.Handle<User> handle;

        public User(Recycler.Handle<User> handle) {
            this.handle = handle;
        }

        public void recycle() {
            handle.recycle(this);
        }
    }
}
